# -*- coding: utf-8 -*-
"""
线程安全的多数据库连接管理器
支持 SQLite / MySQL
"""

import threading
import logging
from typing import Dict
from PySide6.QtSql import QSqlDatabase

from dbService.config import DBConfig

logger = logging.getLogger(__name__)


class ConnectionManager:
    """线程局部存储 + 按配置复用连接"""
    _local = threading.local()

    @classmethod
    def _get_key(cls, config: DBConfig) -> str:
        """生成唯一连接键"""
        if config.type == 'sqlite':
            return f"sqlite://{config.path}"
        elif config.type == 'mysql':
            port = config.port or 3306
            return f"mysql://{config.username}@{config.host}:{port}/{config.database}"
        else:
            raise ValueError(f"不支持的数据库类型: {config.type}")

    @classmethod
    def _get_qt_driver(cls, db_type: str) -> str:
        drivers = {
            'sqlite': 'QSQLITE',
            'mysql': 'QMYSQL',
        }
        if db_type not in drivers:
            raise ValueError(f"Qt 不支持该数据库类型: {db_type}。可用驱动: {list(drivers.keys())}")
        return drivers[db_type]

    @classmethod
    def get_connection(cls, config: DBConfig) -> QSqlDatabase:
        """获取或创建指定配置的数据库连接（线程安全）"""
        if not hasattr(cls._local, 'connections'):
            cls._local.connections = {}  # type: Dict[str, QSqlDatabase]

        key = cls._get_key(config)
        connections = cls._local.connections

        # 复用有效连接
        if key in connections and connections[key].isOpen():
            return connections[key]

        # 清理同名旧连接（防止 Qt 警告）
        conn_name = f"db_conn_{threading.get_ident()}_{abs(hash(key)) % 10000}"
        if QSqlDatabase.contains(conn_name):
            old_db = QSqlDatabase.database(conn_name)
            if old_db.isOpen():
                old_db.close()
            QSqlDatabase.removeDatabase(conn_name)

        # 创建新连接
        driver = cls._get_qt_driver(config.type)
        db = QSqlDatabase.addDatabase(driver, conn_name)

        try:
            if config.type == 'sqlite':
                db.setDatabaseName(config.path)
            elif config.type == 'mysql':
                db.setHostName(config.host)
                db.setPort(config.port or 3306)
                db.setDatabaseName(config.database)
                db.setUserName(config.username)
                db.setPassword(config.password)

            if not db.open():
                error_text = db.lastError().text()
                raise RuntimeError(f"数据库打开失败: {error_text}")

            logger.debug(f"✅ 新建数据库连接: {key} (线程 {threading.get_ident()})")
            connections[key] = db
            return db

        except Exception as e:
            # 清理失败连接
            if QSqlDatabase.contains(conn_name):
                QSqlDatabase.removeDatabase(conn_name)
            raise e

    @classmethod
    def close_all_connections(cls):
        """关闭当前线程所有连接（用于应用退出清理）"""
        if hasattr(cls._local, 'connections'):
            for conn_name, db in list(cls._local.connections.items()):
                if db.isValid() and db.isOpen():
                    name = db.connectionName()
                    db.close()
                    QSqlDatabase.removeDatabase(name)
            cls._local.connections.clear()
            logger.debug("🧹 当前线程所有数据库连接已关闭")